package com.whfc.iot.mach.service.impl;

import com.whfc.common.file.FileHandler;
import com.whfc.hdc.dto.DeviceUpgradeDTO;
import com.whfc.hdc.dto.DeviceUpgradeDataDTO;
import com.whfc.hdc.service.AppDeviceOtaService;
import com.whfc.iot.mach.service.DeviceUpgradeService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/8/23 15:09
 */
@Component
public class DeviceUpgradeServiceImpl implements DeviceUpgradeService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public static final Integer MASTER = 0x01;

    public static final Integer SLAVE = 0x00;

    private String masterOssKeyPattern = "{0}/master_upgrade_{1}_{2}.bin";

    private String slaveOssKeyPattern = "{0}/slave_upgrade_{1}_{2}.bin";

    private String masterCacheKeyPattern = "master_{0}_{1}";

    private String slaveCacheKeyPattern = "slave_{0}_{1}";

    private Object lock = new Object();

    private ConcurrentHashMap<String, List<byte[]>> upgradeDataMap = new ConcurrentHashMap<>(16);

    private int packageSize = 256;

    private int packageMax = 256;

    @DubboReference(interfaceClass = AppDeviceOtaService.class, version = "1.0.0")
    private AppDeviceOtaService upgradeService;

    @Value("${iot.upgrade.oss.dir}")
    private String updateFileOssKey;

    @Autowired
    private FileHandler fileHandler;

    @Override
    public DeviceUpgradeDTO getDeviceUpgrade(Integer deviceType, Integer deviceId, String masterVer, String slaveVer) {
        return upgradeService.getDeviceUpgrade(deviceType, deviceId, masterVer, slaveVer);
    }

    @Override
    public DeviceUpgradeDataDTO getDeviceUpgradeData(Integer deviceType, Integer masterOrSlave, String newVer) throws IOException, InterruptedException {
        String ossKeyPattern = MASTER.equals(masterOrSlave) ? masterOssKeyPattern : slaveOssKeyPattern;
        String cacheKeyPattern = MASTER.equals(masterOrSlave) ? masterCacheKeyPattern : slaveCacheKeyPattern;
        String cacheKey = MessageFormat.format(cacheKeyPattern, deviceType, newVer);
        synchronized (lock) {
            if (!upgradeDataMap.containsKey(cacheKey)) {
                String ossKey = MessageFormat.format(ossKeyPattern, updateFileOssKey, deviceType, newVer);
                File tempFile = File.createTempFile(ossKey, ".bin");
                fileHandler.download(ossKey, tempFile.getPath());
                TimeUnit.SECONDS.sleep(5);

                InputStream inputStream = new FileInputStream(tempFile);
                int c = 0;
                byte[] temp = new byte[packageSize];
                List<byte[]> dataList = new ArrayList<>(packageMax);
                while ((c = inputStream.read(temp)) != -1) {
                    byte[] data = Arrays.copyOf(temp, c);
                    dataList.add(data);
                }
                upgradeDataMap.put(cacheKey, dataList);
            }
        }
        List<byte[]> upgradeDataList = upgradeDataMap.get(cacheKey);
        return DeviceUpgradeDataDTO.builder()
                .deviceType(deviceType)
                .newVer(newVer)
                .subPackageTotal(upgradeDataList.size())
                .subPackageSeq(0)
                .subPackageDataLength(0)
                .build();
    }

    @Override
    public DeviceUpgradeDataDTO getDeviceUpgradeData(Integer deviceType, Integer masterOrSlave, String newVer, int subPackageSeq) {
        String cacheKeyPattern = MASTER.equals(masterOrSlave) ? masterCacheKeyPattern : slaveCacheKeyPattern;
        String cacheKey = MessageFormat.format(cacheKeyPattern, deviceType, newVer);
        List<byte[]> upgradeDataList = upgradeDataMap.get(cacheKey);
        byte[] subPackageData = upgradeDataList.get(subPackageSeq - 1);
        return DeviceUpgradeDataDTO.builder()
                .deviceType(deviceType)
                .newVer(newVer)
                .subPackageTotal(upgradeDataList.size())
                .subPackageSeq(subPackageSeq)
                .subPackageDataLength(subPackageData.length)
                .subPackageData(subPackageData)
                .build();
    }

    @Override
    public void upgradeComplete(Integer deviceId) {
        upgradeService.upgradeComplete(deviceId);
    }

    @Override
    @Async
    public void updateUpgradeProgress(Integer deviceId, Integer masterOrSlave, String newVer, Integer finish, Integer total) {
        upgradeService.updateUpgradeProgress(deviceId, masterOrSlave, newVer, finish, total);
    }
}
